//
// Created by hugan on 2020/12/3.
//
#include "../joystick/JoystickManager.h"
#include "../common/CommonUtil.h"

using namespace std;

/**
 * @param useGuidString true-使用GUID对象启动监听,false-使用GUID字符串启动监听
 */
void testJoystickManager(bool useGuidString) {
    static JoystickManager joystickManager;
    static int stateReceiveCount;

    func_deviceStateCallback deviceStateCallback = [](DIJOYSTATE2 state, HRESULT hr) -> void {
        cout << "deviceStateCallback=" << stateReceiveCount << endl;
        CommonUtil::FAILED2("deviceState", hr);//如果有错误,才打印错误日志
        CommonUtil::printDeviceState(&state, false);
        if (stateReceiveCount++ > 300) joystickManager.stopListenState();//收到n次消息后就退出测试
    };
    if (CommonUtil::FAILED2("createDirectInput8", joystickManager.createDirectInput8(false, deviceStateCallback))) {
        return;
    }

    static string guidString;
    if (!useGuidString) {
        //连接最后一个已连接的设备
        static int devIndex = 0;
        if (CommonUtil::FAILED2("enumDevices", joystickManager.enumDevices([](EnumDeviceData data) -> void {
            devIndex++;
            cout << "dev." << devIndex << "=" << data.tszInstanceName << endl;
            cout << "  guid=" << data.guid << endl;
            //取最后一个设备
            guidString = data.guid;
        }))) {
            return;
        }
        if (!guidString.length()) {
            cout << "device not found" << endl;
            return;//没有设备
        }
        cout << "use last enumDevices Guid=" << guidString << endl;
    } else {
        //连接指定GUID字符串的设备
        guidString = "26B96020-0170-11EB-8003444553540000";
        cout << "use guidString=" << guidString << endl;
    }

    //启动异步线程ExitInputThread
    CommonUtil::startExitInputThread([]() -> void {
        cout << "stopListenState" << endl;
        joystickManager.stopListenState();
    });

    //阻塞当前线程,监听设备:
    int fps[] = {90, 60, 30, 1};
    int stateScanSpan = 1000 / fps[1];
    int stickRange = 2000;
//    bool breakIfErr = true;
    bool breakIfErr = false;
    joystickManager.startListenState(guidString.c_str(), stateScanSpan, stickRange, breakIfErr);
    cout << "listen.out" << endl;
}

/**
 * 测试轮询获取在线设备;
 * 作用:性能分析,使用enumDevices轮询时,会比频繁触发按键还占CPU;
 * 耗能原因猜想:
 *  .enumDevices中,callback频繁产生JNA-CPP调用
 *  .DirectInputApi本身问题
 * 解决方案:
 *  .轮询获取在线设备时,只获取guid:enumDevices本身是为了非频繁列举设备[guid,名字]的,频繁轮询时不适用
 *  .使用vector或链表替换callback模式
 * 实际结论:
 *  .DirectInputApi本身问题,即使调用频率降下来,enumDevices中什么都不做,也是占用CPU的
 * @param useEnumDevices true-使用enumDevices进行轮询
 */
void testGetOnlineDevice(bool useEnumDevices) {

    static bool canRun = true;
    //启动异步线程ExitInputThread
    CommonUtil::startExitInputThread([]() -> void {
        cout << "stopListenState" << endl;
        canRun = false;
    });

    JoystickManager joystickManager;
    joystickManager.createDirectInput8(false, nullptr);
    static int count;

//    DWORD scanSpan = 300;
    DWORD scanSpan = 3000;
    while (canRun) {
        count++;
        cout << "count=" << count << endl;
        if (useEnumDevices) {
            static int devIndex = 0;
            CommonUtil::FAILED2("enumDevices", joystickManager.enumDevices([](EnumDeviceData data) -> void {
                devIndex++;
                cout << "dev." << devIndex << "=" << "  guid=" << data.guid << endl;
            }));
            devIndex = 0;
        } else {
            vector<string> lstOnline = joystickManager.getOnlineGuid();
            for (const auto &item :lstOnline) cout << item << endl;
        }
        Sleep(scanSpan);
    }
}

int main() {
    cout << "st" << endl;

    testJoystickManager(false);
//    testJoystickManager(true);

//    testGetOnlineDevice(true);
//    testGetOnlineDevice(false);

    cout << "ed" << endl;
    return 0;
}